import java.applet.*;
import java.awt.*;
import java.net.*;
import java.awt.event.*;
import java.io.*;
import java.util.StringTokenizer;

//******************************************************************************
// Client.java
// E.Lefran�ois 10 f�vrier 2001
// Projet "Chat", avec soquettes
//******************************************************************************

//==============================================================================
// classe "FenetreApplication"
// -->  Support pour l'application ex�cut�e en mode "Standalone"  (Application
// autonome)
//
// Cette classe agit en tant que fen�tre "top level" dans laquelle s'ex�cute
// l'applet.
//==============================================================================
class FenetreApplication extends Frame {
// Classe imbriqu�e utilis�e pour traiter les �v�nements "fen�tre", comme
// "window closing" notamment.
   class WindowEventListener extends WindowAdapter {
         public void windowClosing (WindowEvent e) {
                a_client.ev_deconnecter();
                System.exit(0);
         }
   }

// Variables d'instance
   private WindowEventListener wEL = new WindowEventListener();

   /**
    * @supplierRole a_client 
    */
   private Client a_client;   // Client associ�

// Constructeur (s)
   public FenetreApplication (Client leClient) {
          setTitle (" C L I E N T - C H A T ");
          addWindowListener (wEL);
          setBackground(Color.lightGray);
          a_client = leClient;
   }
}

//==============================================================================
// Classe Client
// Attend des �v�nements utilisateurs:
//        1) "connecter":  demande de connexion demand�e par l'utilisateur
//        2) "envoyer": un message doit �tre envoy� aux autres clients
//        3) "deconnecter":  demande de d�connexion demand�e par l'utilisateur
//
// Attend des �v�nements g�n�r�s par le serveur
//        1) "sessionAcceptee": la demande de session a �t� accept�e
//        3) "sessionRefusee": la demande de session a �t� refus�e
//        2) "connexionFermee": la connexion est termin�e, et la session par
//            la m�me occasion
//            Causes possibles (non distingu�es)
//                - Normale: suite � demande de d�connexion demand�e par
//                  l'utilisateur
//                - Anormale:  le serveur est "tomb�", probl�me d'I/O
//
// En r�ponse � une demande de connexion de l'utilisateur:
// 1/ une socket est cr��e afin de pouvoir communiquer avec le serveur.
// 2/ le programme cr�e une instance de la classe "Connexion", un objet
//    actif qui sera responsable de la r�ception et de l'analyse des messages
//    envoy�s par le serveur.
//
// En r�ponse � une demande d'envoi, la ligne de texte sp�cifi�e par
// l'utilisateur est envoy�e au serveur.
//
// En r�ponse � une demande de d�connexion, ou lorsque l'application est
// "quitt�e", le message de fin de session est envoy� au serveur.  C'est le
// serveur lui-m�me qui fermera la socket.
//==============================================================================

//------------------------------------------------------------------------------
public class Client extends Applet {
// Constantes de classes
   private static final int NO_PORT = 5002;    // No du port attach� au serveur
// Variables d'instance

   private boolean connexionEnCours = false;
   private boolean sessionEnCours = false;
   private String monId ="";    // Identificateur du client

   private boolean standAloneMode = false;
                   // Si true: ex�cution en tant qu'application "standalone"
                   // Si false: ex�cution en tant qu'applet


   /**
    * @supplierRole fenetre 
    */
   private static FenetreApplication fenetre;
                    // Fen�tre "Top-level" contenant l'applet
                    // Utilis� uniquement en mode "standalone"


   /**
    * @link aggregationByValue 
    */
   private InterfaceUtilisateur gui;
                  // D�finition de l'interface utilisateur (boutons, ..)


   /**
    * @supplierRole socket
    * @link aggregationByValue 
    */
   private Socket socket;
           	  // socket connect�e au serveur


   /**
    * @supplierRole ecouteurDuServeur
    * @link aggregationByValue 
    */
   private ServeurEcouteur ecouteurDuServeur;
                  // Objet actif associ�, qui �coute le serveur de mani�re
                  // concurrente au reste du programme


   /**
    * @supplierRole canalDeSortie 
    */
   //private PrintWriter canalSeSortie;	  // Canal de sortie, pour le texte
                                          // envoy� au serveur
   private ObjectOutputStream canalSeSortie;

   //private DataOutputStream dataOutCanal;
      // Canal de sortie pour les donn�es uniquement:  non utilis� !
      // Pour le cr�er:
      // dataOutCanal = new DataOutputStream (socketWithServer.getOutputStream());



   // Constructeur(s)
   public Client() {}


// M�thodes publiques
   public static void main(String[] args) {
   // Point d'entr�e de l'application, si ex�cut�e en mode "standalone"

   // Cr�ation et d�marrage de l'applet
      Client appletClient = new Client();
      appletClient.standAloneMode = true;

   // Cr�ation de la fen�tre "top-level", dans laquelle s'ex�cute l'applet Client
      fenetre = new  FenetreApplication(appletClient);
      fenetre.add("Center", appletClient);

      appletClient.init();
      fenetre.pack();   // Ajustement de la taille de la fen�tre � la taille
                        // de ses composants
      fenetre.show();
      appletClient.start();
   }

   public void init() {
   // M�thode appel�e lorsque l'applet est charg�e pour la premi�re fois, ou
   // lorsqu'elle est recharg�e.
   // Cette m�thode est utilis�e pour op�rer diverses initialisations
   // (structures de donn�es, composants de la fen�tre, ..)
      gui = new InterfaceUtilisateur(this);
      setLayout (new BorderLayout());
      add (gui, "Center");
      gui.desactiverEtatConnexion();
      gui.desactiverEnvoi();
   }

   public void start() {
   // M�thode appel�e lorsque l'applet est initialis�e (suit le message init()),
   // et � chaque fois que la page qui contient l'applet est � nouveau activ�e
      gui.effacerAvertissement();
      if (! connexionEnCours) demarrerSession();
   }

   public void stop(){}
   // M�thode appel�e lorsque la page qui contient l'applet est d�sactiv�e
   // Le chat continue en arri�re plan

    public void ev_connexionFermee (String message) {
    // Ev�nement envoy� par l'�couteur du serveur
        gui.afficherAvertissement("CONNEXION TERMINEE", message);
        fermerSession();
    }

// Gestion des �v�nements
   public void ev_connecter () {
   // Demande de connexion demand�e par le client
      gui.effacerAvertissement();
      demarrerSession();
   }

   public void ev_deconnecter () {
   // Fin de connexion demand�e par le client
      gui.effacerAvertissement();
      seDeconnecter();

   }

   public void ev_envoyer() {
      if (gui.getMessage().length()!=0)
            //envoyerTexteAuServeur("#DATA#"+gui.getMessage()); 
      		envoyerTexteAuServeur(gui.getMessage()); // Test pour sheepMIx.
   }

// Ev�nements
   public void ev_sessionAcceptee() {
   // Ev�nement envoy� par le serveur (Via �couteur de serveur)
      sessionEnCours = true;
      gui.activerEnvoi();
   }

   public void ev_sessionRefusee(String message) {
   // Ev�nement envoy� par le serveur (Via �couteur de serveur)
      gui.afficherAvertissement("!! SESSION REFUSEE !! ", message);
      seDeconnecter();
   }

   // M�thodes diverses
   public String getIdClient () {return monId; }
   public void setIdClient(String id) {monId = id; }

   // M�thodes priv�es
   private void envoyerTexteAuServeur (String text) {
        if (! connexionEnCours) return;
        String t = text.replace('\n',(char)0);
        try {
            canalSeSortie.writeObject(t);
            canalSeSortie.flush();// le canal a �t� cr�� sans  "automatic flush"
        }
        catch (Exception e) {
             gui.afficherAvertissement
                    ("!! PROBLEME DE CONNEXION !! " , e.toString());
             fermerSession();
        }
   }

   private String saisirIdentificateurClient () {
       monId = null;
       LoginDialogue ld = new LoginDialogue ((Frame)getParent(), this);
       ld.show();
       return monId;
   }

   private void demarrerSession() {
      String id = saisirIdentificateurClient();
      if (id != null) {
          connexionEnCours = seConnecter();
          if (connexionEnCours) {
              gui.activerEtatConnexion();
              envoyerTexteAuServeur("#CTR#LOGIN#"+id);
          }
      }
   }

   private void fermerSession() {
      connexionEnCours = false;
      sessionEnCours = false;
      gui.desactiverEtatConnexion();
      gui.desactiverEnvoi();
      if (socket != null)
        try {socket.close();} catch (IOException e ) {}
   }

   private void seDeconnecter() {
       if (connexionEnCours) {    // Programmation d�fensive
             envoyerTexteAuServeur ("#CTR#LOGOUT");
      }
   }

   private boolean seConnecter () {
   // Retourne "true" si la connexion est �tablie, "false" dans les autres cas
        if (connexionEnCours) return true;

        InetAddress adresseIP;
        //------------ Essayer l'adresse
        try {
            //adresseIP = InetAddress.getByName("xxx.xxx.xxx.xxx");
            adresseIP = InetAddress.getLocalHost();   // Connexion en local
            //System.out.println( adresseIP.getHostAddress());
            //System.out.println( adresseIP.getHostName());
        }
        catch (UnknownHostException e) {
              gui.afficherAvertissement
                   ("!! PROBLEME DE CONNEXION !!", e.toString());
              return false;
        }
        //------------- Cr�ation de la socket permettant de communiquer avec
        //              le serveur
        try {
            socket = new Socket (adresseIP, NO_PORT);
        }
        catch (IOException e) {
              gui.afficherAvertissement
                   ("!! PROBLEME DE CONNEXION !!" ,e.toString());
              return false;
        }
        //------------- Ouverture des canaux d'entr�e et de sortie
        try {
            canalSeSortie = new ObjectOutputStream
                              (socket.getOutputStream());
            ecouteurDuServeur = new ServeurEcouteur
                                   (socket.getInputStream(),
                                    gui,
                                    this);

            return true;    // Connexion OK
        }
        catch (IOException e) {
            try {socket.close(); } catch (IOException ioe) {};
            gui.afficherAvertissement
                   ("!! PROBLEME DE CONNEXION !!", e.toString());
            return false;
        }
   }
}

